﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;

namespace nyxwin.Main.Utils
{
    public sealed class IconCache
    {
        #region Singleton
        private static IconCache _instance = null;
        private static object _static_lock = new object();

        public static IconCache Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_static_lock)
                    {
                        if (_instance == null)
                        {
                            _instance = new IconCache();
                        }
                    }
                }

                return _instance;
            }
        }
        #endregion

        private object _lock;
        private Dictionary<string, DateTime> _lastDownload;
        private Dictionary<string, List<Action<Stream>>> _registeredActions;

        private static readonly TimeSpan MIN_DOWNLOAD_SPAN = new TimeSpan(0, 5, 0);

        private IconCache()
        {
            _lock = new object();
            _lastDownload = new Dictionary<string, DateTime>();
            _registeredActions = new Dictionary<string, List<Action<Stream>>>();
        }

        public void GetStream(string uri, Action<Stream> callBack)
        {
            lock (_lock)
            {
                if (_registeredActions.ContainsKey(uri))
                {
                    _registeredActions[uri].Add(callBack);
                    return;
                }
                else
                {
                    _registeredActions.Add(uri, new List<Action<Stream>>());
                    _registeredActions[uri].Add(callBack);
                }
            }

            GetStream(uri);
        }

        private void GetStream(string uri)
        {
            if (_lastDownload.ContainsKey(uri))
            {
                if ((DateTime.Now - _lastDownload[uri]) <= MIN_DOWNLOAD_SPAN)
                {
                    ProcessActionsAfterDownload(uri);
                    return;
                }
            }

            WebClient wc = new WebClient();
            wc.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
            wc.OpenReadAsync(new Uri(uri, UriKind.Absolute), uri);
        }

        void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            var uri = e.UserState as string;
            var picName = GenerateIsoUriFromUri(uri);

            Stream data = null;

            if (!e.Cancelled && e.Error == null)
            {
                data = e.Result;
            }

            using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication())
            {
                CheckDirectory(isoStore);

                if (isoStore.FileExists(picName))
                {
                    isoStore.DeleteFile(picName);
                }

                if (data != null)
                {
                    using (var isoFile = isoStore.CreateFile(picName))
                    {
                        long len = data.Length;
                        byte[] b = new byte[len];
                        data.Read(b, 0, b.Length);
                        isoFile.Write(b, 0, b.Length);
                        isoFile.Flush();
                    }
                }
            }

            lock (_lock)
            {
                if (!_lastDownload.ContainsKey(uri))
                    _lastDownload.Add(uri, DateTime.Now);
                else
                    _lastDownload[uri] = DateTime.Now;
            }

            ProcessActionsAfterDownload(uri);
        }

        private void CheckDirectory(IsolatedStorageFile isoStore)
        {
            if (!isoStore.DirectoryExists("nyx-icons"))
                isoStore.CreateDirectory("nyx-icons");
        }

        private void ProcessActionsAfterDownload(string uri)
        {
            var picName = GenerateIsoUriFromUri(uri);

            lock (_lock)
            {
                using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    CheckDirectory(isoStore);

                    foreach (var action in _registeredActions[uri])
                    {
                        if (isoStore.FileExists(picName))
                        {
                            var isoFile = isoStore.OpenFile(picName, FileMode.Open, FileAccess.Read);
                            action(isoFile);
                        }
                        else
                        {
                            action(null);
                        }
                    }
                }

                _registeredActions.Remove(uri);
            }
        }

        private string GenerateIsoUriFromUri(string uri)
        {
            var from = uri.LastIndexOf('/') + 1;
            var picName = uri.Substring(from);

            return "nyx-icons/" + picName;
        }
    }
}
